const express = require('express');
const cors = require('cors');
const path = require('path');
const fs = require('fs-extra');
const { spawn } = require('child_process');
const http = require('http');
const socketIo = require('socket.io');
const multer = require('multer');
const YouTubeDownloader = require('./downloader');
const VideoProcessor = require('./videoProcessor');

const app = express();
const server = http.createServer(app);
const io = socketIo(server, {
  cors: {
    origin: "*",
    methods: ["GET", "POST"]
  }
});

const PORT = process.env.PORT || 3001;

// 配置 multer 用于文件上传
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    const uploadsDir = path.join(__dirname, '../uploads');
    // 确保uploads目录存在
    if (!fs.existsSync(uploadsDir)) {
      fs.mkdirSync(uploadsDir, { recursive: true });
    }
    cb(null, uploadsDir);
  },
  filename: function (req, file, cb) {
    // 生成唯一文件名，保留原始扩展名
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    const ext = path.extname(file.originalname);
    const name = path.basename(file.originalname, ext);
    cb(null, `${name}-${uniqueSuffix}${ext}`);
  }
});

const upload = multer({
  storage: storage,
  limits: {
    fileSize: 10 * 1024 * 1024, // 10MB 限制
  },
  fileFilter: function (req, file, cb) {
    // 允许图片文件和文本文件（用于字幕）
    const allowedImageTypes = /jpeg|jpg|png|gif|bmp|webp|svg/;
    const allowedTextTypes = /txt|srt|vtt|ass|ssa|sub/;
    const extname = allowedImageTypes.test(path.extname(file.originalname).toLowerCase()) ||
                   allowedTextTypes.test(path.extname(file.originalname).toLowerCase());
    const mimetype = allowedImageTypes.test(file.mimetype) || file.mimetype.includes('text') || file.mimetype === 'text/plain';
    
    if (mimetype && extname) {
      return cb(null, true);
    } else {
      cb(new Error('只允许上传图片文件或文本文件！'));
    }
  }
});

// 中间件
app.use(cors());
app.use(express.json());
app.use(express.static(path.join(__dirname, '../public')));
// 配置downloads目录的静态文件服务，用于访问预览图片等文件
app.use('/downloads', express.static(path.join(__dirname, '../downloads')));
// 配置uploads目录的静态文件服务，用于访问背景图片等文件
app.use('/uploads', express.static(path.join(__dirname, '../uploads')));

// 初始化下载器和视频处理器
const downloadDir = path.join(__dirname, '../downloads');
const downloader = new YouTubeDownloader(downloadDir);
const videoProcessor = new VideoProcessor(downloadDir);

// 下载视频或播放列表（使用 Socket.IO）
async function downloadVideoWithSocket(url, options = {}, socketId = null) {
  const socket = socketId ? io.to(socketId) : null;
  
  // 智能重试配置
  const maxRetries = 6;
  const retryDelays = [3000, 6000, 12000, 24000, 48000, 60000]; // 递增延迟，最长1分钟
  const maxDelay = 60000; // 最大延迟60秒
  
  // Fallback策略配置
  const fallbackStrategies = [
    { name: '标准模式', config: 'standard' },
    { name: 'iOS客户端模式', config: 'ios' },
    { name: 'Android客户端模式', config: 'android' },
    { name: 'TV客户端模式', config: 'tv' },
    { name: '基础模式', config: 'basic' },
    { name: '无cookies模式', config: 'no-cookies' },
    { name: '兼容模式', config: 'compatibility' },
    { name: '紧急模式', config: 'emergency' }
  ];
  
  // 主下载函数
  async function attemptDownload(retryCount = 0, fallbackIndex = 0) {
    try {
      // 首先获取视频信息
      let videoInfo;
      try {
        videoInfo = await downloader.getVideoInfo(url);
        if (socket) {
          socket.emit('download-progress', { message: `获取到视频信息: ${videoInfo.title}` });
        }
      } catch (error) {
        videoInfo = { title: 'unknown_video' };
        if (socket) {
          socket.emit('download-progress', { message: '无法获取视频信息，使用默认名称' });
        }
      }

      // 创建下载目录
      const downloadPath = downloader.createDownloadPath(videoInfo.title, null, url);
      if (socket) {
        socket.emit('download-progress', { message: `创建下载目录: ${downloadPath}` });
      }

      // 设置输出模板
      let outputTemplate = path.join(downloadPath, '%(title)s.%(ext)s');
      
      const args = [
        url,
        '--output', outputTemplate,
        '--format', options.quality || 'best',
        '--write-info-json',
        '--write-thumbnail'
      ];

      // 添加预设别名支持（yt-dlp 2025.08.20新功能）
      if (options.preset) {
        args.push('--preset-alias', options.preset);
        if (socket) {
          socket.emit('download-progress', { message: `使用预设: ${options.preset}` });
        }
      }

      // 播放列表选项
      if (options.playlist) {
        args.push('--yes-playlist');
        // 对于播放列表，使用不同的输出模板
        outputTemplate = path.join(downloadPath, '%(playlist_index)s - %(title)s.%(ext)s');
        args[args.indexOf(args[2])] = outputTemplate;
      } else {
        args.push('--no-playlist');
      }

      // 音频格式选项
      if (options.audioOnly) {
        args.push('--extract-audio', '--audio-format', options.audioFormat || 'mp3');
      }

      // 字幕选项
      if (options.subtitles) {
        args.push('--write-subs', '--write-auto-subs', '--sub-lang', options.subtitleLang || 'en');
      }

      // 根据当前策略添加配置
      const currentStrategy = fallbackStrategies[fallbackIndex];
      if (socket) {
        socket.emit('download-progress', { message: `使用策略: ${currentStrategy.name}` });
      }
      
      // 添加基础网络配置
      args.push('--retries', '15');
      args.push('--fragment-retries', '15');
      args.push('--socket-timeout', '60');
      args.push('--sleep-requests', Math.floor(Math.random() * 3) + 1); // 随机延迟1-3秒
      args.push('--http-chunk-size', '10M');
      args.push('--hls-prefer-native');
      args.push('--abort-on-unavailable-fragment');
      args.push('--no-check-formats');
      
      // 反检测配置
      args.push('--add-header', 'Accept-Language:en-US,en;q=0.9');
      args.push('--add-header', 'Accept-Encoding:gzip, deflate, br');
      args.push('--add-header', 'Cache-Control:no-cache');
      args.push('--add-header', 'Pragma:no-cache');
      args.push('--add-header', 'Sec-Fetch-Dest:document');
      args.push('--add-header', 'Sec-Fetch-Mode:navigate');
      args.push('--add-header', 'Sec-Fetch-Site:none');
      args.push('--add-header', 'Upgrade-Insecure-Requests:1');
      
      // 代理配置（如果环境变量中有代理设置）
      if (process.env.HTTP_PROXY) {
        args.push('--proxy', process.env.HTTP_PROXY);
      }
      if (process.env.HTTPS_PROXY) {
        args.push('--proxy', process.env.HTTPS_PROXY);
      }
      
      // 策略特定配置
      switch (currentStrategy.config) {
        case 'standard':
          // 标准模式：完整cookies + 强化验证绕过
          const cookiesPath = path.join(__dirname, '../cookies/youtube_cookies.txt');
          if (fs.existsSync(cookiesPath)) {
            args.push('--cookies', cookiesPath);
          }
          try {
            args.push('--cookies-from-browser', 'chrome:Default');
          } catch (e) {
            console.log('Chrome cookies提取失败，跳过');
          }
          args.push('--extractor-args', 'youtube:player_client=web;formats=missing_pot;playback_wait=5');
          args.push('--user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
          break;
          
        case 'ios':
          // iOS客户端模式：模拟iOS YouTube应用
          args.push('--extractor-args', 'youtube:player_client=ios;formats=missing_pot');
          args.push('--user-agent', 'com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)');
          args.push('--sleep-interval', '2');
          break;
          
        case 'android':
          // Android客户端模式：模拟Android YouTube应用
          args.push('--extractor-args', 'youtube:player_client=android;formats=missing_pot');
          args.push('--user-agent', 'com.google.android.youtube/19.09.37 (Linux; U; Android 11) gzip');
          args.push('--sleep-interval', '3');
          break;
          
        case 'tv':
          // TV客户端模式：模拟YouTube TV应用
          args.push('--extractor-args', 'youtube:player_client=tv_embedded;formats=missing_pot');
          args.push('--user-agent', 'Mozilla/5.0 (SMART-TV; Linux; Tizen 2.4.0) AppleWebKit/538.1');
          args.push('--sleep-interval', '4');
          break;
          
        case 'basic':
          // 基础模式：简化配置
          args.push('--extractor-args', 'youtube:player_client=web;formats=missing_pot');
          args.push('--user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
          break;
          
        case 'no-cookies':
          // 无cookies模式：纯净配置
          args.push('--extractor-args', 'youtube:player_client=web');
          args.push('--user-agent', 'Mozilla/5.0 (compatible; Googlebot/2.1)');
          break;
          
        case 'compatibility':
          // 兼容模式：最大兼容性
          args.push('--extractor-args', 'youtube:player_client=android');
          args.push('--user-agent', 'com.google.android.youtube/17.36.4');
          args.push('--format', 'worst');
          break;
          
        case 'emergency':
          // 紧急模式：最小化配置，绕过所有检测
          args.push('--extractor-args', 'youtube:player_client=web');
          args.push('--user-agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36');
          args.push('--format', 'worst');
          args.push('--no-check-formats');
          args.push('--ignore-errors');
          args.push('--sleep-interval', '5');
          break;
      }

      return new Promise((resolve, reject) => {
        const ytdlp = spawn('yt-dlp', args);
        let output = '';
        let error = '';

        ytdlp.stdout.on('data', (data) => {
          const message = data.toString();
          output += message;
          
          if (socket) {
            socket.emit('download-progress', { message: message.trim() });
          }
          
          console.log(message);
        });

        ytdlp.stderr.on('data', (data) => {
          const message = data.toString();
          error += message;
          
          if (socket) {
            socket.emit('download-progress', { message: `警告: ${message.trim()}` });
          }
          
          console.error(message);
        });

        ytdlp.on('close', (code) => {
          if (code === 0) {
            if (socket) {
              socket.emit('download-complete', { 
                message: '下载完成!',
                downloadPath: downloadPath,
                videoTitle: videoInfo.title
              });
            }
            resolve({ 
              success: true, 
              output,
              downloadPath: downloadPath,
              videoTitle: videoInfo.title
            });
          } else {
            // 智能错误分析
            const errorMessage = analyzeDownloadError(error);
            console.error(`下载尝试 ${retryCount + 1} 失败: ${errorMessage}`);
            
            if (socket) {
              socket.emit('download-progress', { message: `下载尝试 ${retryCount + 1} 失败: ${errorMessage}` });
            }
            
            reject(new Error(errorMessage));
          }
        });

        ytdlp.on('error', (err) => {
          console.error('yt-dlp 执行失败:', err.message);
          if (socket) {
            socket.emit('download-progress', { message: `执行错误: ${err.message}` });
          }
          reject(new Error('yt-dlp 执行失败: ' + err.message));
        });
      });
    } catch (error) {
      console.error('下载配置失败:', error.message);
      throw error;
    }
  }
  
  // 智能错误分析函数
  function analyzeDownloadError(error) {
    const errorTypes = {
      botVerification: error.includes('Sign in to confirm you') || error.includes('not a bot'),
      networkError: error.includes('handshake operation timed out') || 
                   error.includes('远程主机强迫关闭了一个现有的连接') ||
                   error.includes('WinError 10054') ||
                   error.includes('SSL') ||
                   error.includes('timeout'),
      fragmentError: error.includes('fragment') && error.includes('not found'),
      poTokenError: error.includes('PO Token') || error.includes('po token') || error.includes('HTTP Error 403'),
      formatError: error.includes('No video formats found') || error.includes('Requested format is not available'),
      geoError: error.includes('not available in your country') || error.includes('geo-blocked'),
      privateError: error.includes('Private video') || error.includes('This video is private')
    };
    
    if (errorTypes.botVerification) {
      return '需要验证非机器人，已配置cookies和验证绕过机制';
    } else if (errorTypes.networkError) {
      return '网络连接不稳定，正在重试';
    } else if (errorTypes.fragmentError) {
      return '视频片段获取失败';
    } else if (errorTypes.poTokenError) {
      return 'YouTube验证失败，尝试其他策略';
    } else if (errorTypes.formatError) {
      return '视频格式不可用';
    } else if (errorTypes.geoError) {
      return '地理位置限制';
    } else if (errorTypes.privateError) {
      return '私有视频或已删除';
    } else {
      return error;
    }
  }
  
  // 主重试逻辑
  try {
    for (let fallbackIndex = 0; fallbackIndex < fallbackStrategies.length; fallbackIndex++) {
      for (let retryCount = 0; retryCount < maxRetries; retryCount++) {
        try {
          const result = await attemptDownload(retryCount, fallbackIndex);
          return result;
        } catch (error) {
          const isLastRetry = retryCount === maxRetries - 1;
          const isLastFallback = fallbackIndex === fallbackStrategies.length - 1;
          
          if (isLastRetry && !isLastFallback) {
            // 尝试下一个fallback策略
            console.log(`所有重试失败，尝试fallback策略: ${fallbackStrategies[fallbackIndex + 1].name}`);
            if (socket) {
              socket.emit('download-progress', { message: `尝试fallback策略: ${fallbackStrategies[fallbackIndex + 1].name}` });
            }
            break;
          } else if (isLastRetry && isLastFallback) {
            // 尝试备用提取器
            console.log('所有yt-dlp策略失败，尝试备用提取器...');
            if (socket) {
              socket.emit('download-progress', { message: '尝试备用提取器: gallery-dl' });
            }
            
            try {
              const galleryResult = await tryGalleryDl(url, options, socket);
              return galleryResult;
            } catch (galleryError) {
              console.error('gallery-dl也失败了:', galleryError.message);
              
              // 尝试其他备用方案
              try {
                const alternativeResult = await tryAlternativeExtractors(url, options, socket);
                return alternativeResult;
              } catch (altError) {
                console.error('所有备用提取器都失败了:', altError.message);
                
                // 最终失败
                console.error('最终下载失败: 所有下载策略和备用提取器都失败');
                if (socket) {
                  socket.emit('download-error', { 
                    message: '最终下载失败: YouTube反机器人检测过于严格，所有下载策略都失败。建议:\n1. 稍后重试\n2. 使用浏览器登录后重新尝试\n3. 考虑使用其他视频源' 
                  });
                }
                throw new Error('所有下载策略和备用提取器都失败');
              }
            }
          } else {
            // 等待后重试
            const delay = retryDelays[retryCount] || 16000;
            console.log(`等待 ${delay}ms 后进行第 ${retryCount + 2} 次重试...`);
            if (socket) {
              socket.emit('download-progress', { message: `等待 ${delay}ms 后进行第 ${retryCount + 2} 次重试...` });
            }
            await new Promise(resolve => setTimeout(resolve, delay));
          }
        }
      }
    }
  } catch (error) {
    console.error('下载过程发生错误:', error.message);
    if (socket) {
      socket.emit('download-error', { message: '下载过程发生错误: ' + error.message });
    }
    throw error;
  }
}

// 备用提取器: gallery-dl
async function tryGalleryDl(url, options = {}, socket = null) {
  return new Promise((resolve, reject) => {
    console.log('尝试使用 gallery-dl 下载视频...');
    
    if (socket) {
      socket.emit('download-progress', { message: '使用 gallery-dl 提取视频信息...' });
    }
    
    // 检查 gallery-dl 是否可用
    const checkCmd = spawn('gallery-dl', ['--version'], { shell: true });
    
    checkCmd.on('error', (error) => {
      console.log('gallery-dl 未安装，跳过此备用方案');
      reject(new Error('gallery-dl 未安装'));
    });
    
    checkCmd.on('close', (code) => {
      if (code !== 0) {
        reject(new Error('gallery-dl 不可用'));
        return;
      }
      
      // gallery-dl 可用，尝试下载
      const downloadPath = path.join(downloadDir, 'gallery-dl');
      if (!fs.existsSync(downloadPath)) {
        fs.mkdirSync(downloadPath, { recursive: true });
      }
      
      const args = [
        '--dest', downloadPath,
        '--filename', '{title}.{ext}',
        '--write-info-json',
        url
      ];
      
      const galleryProcess = spawn('gallery-dl', args, { shell: true });
      let output = '';
      let errorOutput = '';
      
      galleryProcess.stdout.on('data', (data) => {
        output += data.toString();
        console.log('gallery-dl output:', data.toString());
        if (socket) {
          socket.emit('download-progress', { message: `gallery-dl: ${data.toString().trim()}` });
        }
      });
      
      galleryProcess.stderr.on('data', (data) => {
        errorOutput += data.toString();
        console.log('gallery-dl error:', data.toString());
      });
      
      galleryProcess.on('close', (code) => {
        if (code === 0) {
          console.log('gallery-dl 下载成功');
          if (socket) {
            socket.emit('download-complete', { 
              message: '使用 gallery-dl 下载完成',
              path: downloadPath
            });
          }
          resolve({ success: true, path: downloadPath, method: 'gallery-dl' });
        } else {
          console.log('gallery-dl 下载失败:', errorOutput);
          reject(new Error(`gallery-dl 失败: ${errorOutput}`));
        }
      });
    });
  });
}

// 其他备用提取器
async function tryAlternativeExtractors(url, options = {}, socket = null) {
  console.log('尝试其他备用提取器...');
  
  if (socket) {
    socket.emit('download-progress', { message: '尝试备用下载方案...' });
  }
  
  // 尝试使用 youtube-dl (如果可用)
  try {
    const youtubeDlResult = await tryYoutubeDl(url, options, socket);
    return youtubeDlResult;
  } catch (error) {
    console.log('youtube-dl 也失败了:', error.message);
  }
  
  // 尝试直接提取视频信息（仅获取元数据）
  try {
    const metadataResult = await tryMetadataOnly(url, options, socket);
    return metadataResult;
  } catch (error) {
    console.log('元数据提取也失败了:', error.message);
  }
  
  throw new Error('所有备用提取器都失败');
}

// 尝试 youtube-dl
async function tryYoutubeDl(url, options = {}, socket = null) {
  return new Promise((resolve, reject) => {
    console.log('尝试使用 youtube-dl...');
    
    if (socket) {
      socket.emit('download-progress', { message: '尝试 youtube-dl...' });
    }
    
    const checkCmd = spawn('youtube-dl', ['--version'], { shell: true });
    
    checkCmd.on('error', (error) => {
      reject(new Error('youtube-dl 未安装'));
    });
    
    checkCmd.on('close', (code) => {
      if (code !== 0) {
        reject(new Error('youtube-dl 不可用'));
        return;
      }
      
      const downloadPath = path.join(downloadDir, 'youtube-dl');
      if (!fs.existsSync(downloadPath)) {
        fs.mkdirSync(downloadPath, { recursive: true });
      }
      
      const args = [
        '--output', path.join(downloadPath, '%(title)s.%(ext)s'),
        '--write-info-json',
        '--no-check-certificate',
        url
      ];
      
      const dlProcess = spawn('youtube-dl', args, { shell: true });
      let output = '';
      let errorOutput = '';
      
      dlProcess.stdout.on('data', (data) => {
        output += data.toString();
        if (socket) {
          socket.emit('download-progress', { message: `youtube-dl: ${data.toString().trim()}` });
        }
      });
      
      dlProcess.stderr.on('data', (data) => {
        errorOutput += data.toString();
      });
      
      dlProcess.on('close', (code) => {
        if (code === 0) {
          resolve({ success: true, path: downloadPath, method: 'youtube-dl' });
        } else {
          reject(new Error(`youtube-dl 失败: ${errorOutput}`));
        }
      });
    });
  });
}

// 仅提取元数据
async function tryMetadataOnly(url, options = {}, socket = null) {
  console.log('尝试仅提取视频元数据...');
  
  if (socket) {
    socket.emit('download-progress', { message: '提取视频元数据...' });
  }
  
  return new Promise((resolve, reject) => {
    const args = [
      '--dump-json',
      '--no-download',
      '--no-check-certificate',
      '--user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
      url
    ];
    
    const process = spawn('yt-dlp', args, { shell: true });
    let output = '';
    let errorOutput = '';
    
    process.stdout.on('data', (data) => {
      output += data.toString();
    });
    
    process.stderr.on('data', (data) => {
      errorOutput += data.toString();
    });
    
    process.on('close', (code) => {
      if (code === 0 && output.trim()) {
        try {
          const metadata = JSON.parse(output.trim());
          console.log('成功提取视频元数据:', metadata.title);
          
          if (socket) {
            socket.emit('download-progress', { 
              message: `获取到视频信息: ${metadata.title}，但无法下载视频文件` 
            });
            socket.emit('download-error', { 
              message: '仅获取到视频元数据，由于YouTube限制无法下载视频文件。建议使用浏览器手动下载或稍后重试。',
              metadata: {
                title: metadata.title,
                duration: metadata.duration,
                uploader: metadata.uploader,
                view_count: metadata.view_count
              }
            });
          }
          
          resolve({ 
            success: false, 
            metadata: metadata, 
            method: 'metadata-only',
            message: '仅获取到元数据，无法下载视频文件'
          });
        } catch (parseError) {
          reject(new Error('元数据解析失败'));
        }
      } else {
        reject(new Error(`元数据提取失败: ${errorOutput}`));
      }
    });
  });
}

// API 路由
app.get('/api/check', async (req, res) => {
  try {
    const isAvailable = await downloader.checkYtDlp();
    res.json({ available: isAvailable });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// 检查 YouTube 连接状态
app.get('/api/check-youtube', async (req, res) => {
  console.log('开始检查 YouTube 连接...');
  
  try {
    const https = require('https');
    const http = require('http');
    const { URL } = require('url');
    
    const testUrl = 'https://www.youtube.com';
    console.log('请求 YouTube 主页:', testUrl);
    
    const urlObj = new URL(testUrl);
    const isHttps = urlObj.protocol === 'https:';
    const requestModule = isHttps ? https : http;
    let responseSent = false; // 添加标志防止重复发送响应
    
    const options = {
      hostname: urlObj.hostname,
      port: urlObj.port || (isHttps ? 443 : 80),
      path: urlObj.pathname,
      method: 'GET',
      timeout: 10000, // 10秒超时
      headers: {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
      }
    };

    const request = requestModule.request(options, (response) => {
      if (responseSent) return; // 防止重复发送响应
      responseSent = true;
      
      console.log(`YouTube 响应状态码: ${response.statusCode}`);
      
      // 检查状态码，200-299 都认为是成功
      if (response.statusCode >= 200 && response.statusCode < 400) {
        console.log('YouTube 连接检查成功');
        res.json({ 
          accessible: true, 
          message: 'YouTube 连接正常',
          status: 'success',
          statusCode: response.statusCode
        });
      } else {
        // 只在连接失败时输出响应头用于调试
        console.log(`响应头:`, response.headers);
        console.log('YouTube 连接失败，状态码:', response.statusCode);
        res.json({ 
          accessible: false, 
          message: `YouTube 访问异常 (状态码: ${response.statusCode})`,
          status: 'error',
          statusCode: response.statusCode
        });
      }
    });

    request.on('timeout', () => {
      if (responseSent) return; // 防止重复发送响应
      responseSent = true;
      
      console.log('YouTube 连接检查超时');
      request.destroy();
      res.json({ 
        accessible: false, 
        message: '连接 YouTube 超时',
        status: 'timeout',
        error: '请求超时'
      });
    });

    request.on('error', (err) => {
      if (responseSent) return; // 防止重复发送响应
      responseSent = true;
      
      console.error('YouTube 连接检查错误:', err.message);
      
      let message = '无法连接到 YouTube';
      if (err.code === 'ENOTFOUND') {
        message = 'DNS 解析失败，请检查网络连接';
      } else if (err.code === 'ECONNREFUSED') {
        message = '连接被拒绝，可能需要代理';
      } else if (err.code === 'ETIMEDOUT') {
        message = '连接超时，请检查网络';
      }
      
      res.json({ 
        accessible: false, 
        message: message,
        status: 'error',
        error: err.message,
        errorCode: err.code
      });
    });

    // 发送请求
    request.end();

  } catch (error) {
    console.error('YouTube 连接检查异常:', error);
    if (!res.headersSent) { // 检查响应头是否已发送
      res.status(500).json({ 
        accessible: false,
        message: '检查 YouTube 连接失败',
        status: 'error',
        error: error.message 
      });
    }
  }
});

app.post('/api/info', async (req, res) => {
  try {
    const { url } = req.body;
    
    // URL参数验证
    if (!url || typeof url !== 'string') {
      return res.status(400).json({ error: 'URL参数无效或缺失' });
    }
    
    // 去除前后空格
    const trimmedUrl = url.trim();
    
    // 检查URL格式
    try {
      new URL(trimmedUrl);
    } catch (urlError) {
      return res.status(400).json({ error: '无效的URL格式' });
    }
    
    // 检查是否为支持的视频平台
    const supportedDomains = [
      'youtube.com', 'youtu.be', 'm.youtube.com',
      'bilibili.com', 'b23.tv', 'm.bilibili.com'
    ];
    
    const isSupported = supportedDomains.some(domain => 
      trimmedUrl.includes(domain)
    );
    
    if (!isSupported) {
      return res.status(400).json({ 
        error: '不支持的视频平台，仅支持 YouTube 和 Bilibili' 
      });
    }
    
    const info = await downloader.getVideoInfo(trimmedUrl);
    res.json(info);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.post('/api/download', async (req, res) => {
  try {
    const { url, options } = req.body;
    const result = await downloader.downloadVideo(url, options);
    res.json(result);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.get('/api/downloads', async (req, res) => {
  try {
    const files = await downloader.getDownloadedFiles();
    const filesByDate = await downloader.getDownloadedFilesByDate();
    res.json({ 
      files, 
      filesByDate,
      totalFiles: files.length 
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// 获取文件列表（用于文件选择器）
app.get('/api/files', async (req, res) => {
  try {
    const files = await downloader.getDownloadedFiles();
    
    // 转换为文件选择器需要的格式
    const fileList = files.map(file => {
      const stats = fs.existsSync(file.path) ? fs.statSync(file.path) : null;
      return {
        name: file.filename,
        path: file.path,
        size: stats ? stats.size : 0,
        date: stats ? stats.mtime.toISOString() : null,
        type: path.extname(file.path).toLowerCase(),
        exists: !!stats
      };
    }).filter(file => file.exists); // 只返回存在的文件
    
    res.json({
      files: fileList,
      totalFiles: fileList.length
    });
  } catch (error) {
    console.error('获取文件列表失败:', error);
    res.status(500).json({ error: error.message });
  }
});

// 获取图片文件列表（用于背景图选择器）
app.get('/api/images', async (req, res) => {
  try {
    const uploadsDir = path.join(__dirname, '..', 'uploads');
    
    // 确保uploads目录存在
    if (!fs.existsSync(uploadsDir)) {
      fs.mkdirSync(uploadsDir, { recursive: true });
    }
    
    // 支持的图片格式
    const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'];
    
    // 读取uploads目录中的所有文件
    const files = fs.readdirSync(uploadsDir);
    
    // 过滤出图片文件并获取详细信息
    const imageFiles = files
      .filter(file => {
        const ext = path.extname(file).toLowerCase();
        return imageExtensions.includes(ext);
      })
      .map(file => {
        const filePath = path.join(uploadsDir, file);
        const stats = fs.statSync(filePath);
        return {
          name: file,
          path: `/uploads/${file}`, // 相对于服务器根目录的路径
          fullPath: filePath,
          size: stats.size,
          date: stats.mtime.toISOString(),
          type: path.extname(file).toLowerCase(),
          exists: true
        };
      })
      .sort((a, b) => new Date(b.date) - new Date(a.date)); // 按修改时间倒序排列
    
    res.json({
      images: imageFiles,
      totalImages: imageFiles.length
    });
  } catch (error) {
    console.error('获取图片文件列表失败:', error);
    res.status(500).json({ error: error.message });
  }
});

// 上传图片文件
app.post('/api/upload-images', upload.array('images', 10), async (req, res) => {
  try {
    if (!req.files || req.files.length === 0) {
      return res.status(400).json({ error: '没有上传任何文件' });
    }

    // 处理上传的文件信息
    const uploadedFiles = req.files.map(file => ({
      name: file.filename,
      originalName: file.originalname,
      path: `/uploads/${file.filename}`,
      fullPath: file.path,
      size: file.size,
      type: path.extname(file.originalname).toLowerCase(),
      date: new Date().toISOString(),
      exists: true
    }));

    console.log(`成功上传 ${uploadedFiles.length} 个图片文件`);

    res.json({
      success: true,
      message: `成功上传 ${uploadedFiles.length} 个图片文件`,
      files: uploadedFiles
    });
  } catch (error) {
    console.error('上传图片失败:', error);
    res.status(500).json({ error: '上传图片失败: ' + error.message });
  }
});

app.get('/api/downloads/by-date', async (req, res) => {
  try {
    const filesByDate = await downloader.getDownloadedFilesByDate();
    res.json(filesByDate);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// 获取搜索关系数据
app.get('/api/search-relations', async (req, res) => {
  try {
    const relations = downloader.getSearchRelations();
    res.json(relations);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// 获取按搜索关键字分组的文件
app.get('/api/downloads/by-search', async (req, res) => {
  try {
    const relations = downloader.getSearchRelations();
    const filesByDate = await downloader.getDownloadedFilesByDate();
    
    // 构建按搜索关键字分组的数据结构
    const filesBySearch = {};
    
    // 遍历搜索关系
    Object.keys(relations).forEach(originalKeyword => {
      const relation = relations[originalKeyword];
      filesBySearch[originalKeyword] = {
        sanitizedKeyword: relation.sanitizedKeyword,
        createdAt: relation.createdAt,
        files: relation.files.map(file => {
          // 尝试从文件系统中获取更多文件信息
          const stats = fs.existsSync(file.path) ? fs.statSync(file.path) : null;
          return {
            ...file,
            exists: !!stats,
            size: stats ? stats.size : 0,
            modifiedAt: stats ? stats.mtime.toISOString() : null
          };
        }).filter(file => file.exists) // 只返回存在的文件
      };
    });
    
    res.json({
      filesBySearch,
      filesByDate,
      totalKeywords: Object.keys(filesBySearch).length,
      totalFiles: Object.values(filesBySearch).reduce((sum, group) => sum + group.files.length, 0)
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// 获取实际目录结构
app.get('/api/downloads/directory-structure', async (req, res) => {
  try {
    const directoryStructure = await downloader.getDirectoryStructure();
    res.json(directoryStructure);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// 获取扫描统计信息
app.get('/api/downloads/scan-stats', async (req, res) => {
  try {
    const stats = await downloader.getScanStats();
    res.json(stats);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// 强制执行全量扫描
app.post('/api/downloads/force-scan', async (req, res) => {
  try {
    const { type = 'full' } = req.body;
    
    if (type === 'full') {
      await downloader.performFullScan();
      res.json({ 
        success: true, 
        message: '全量扫描已完成',
        type: 'full'
      });
    } else if (type === 'incremental') {
      await downloader.performIncrementalScan();
      res.json({ 
        success: true, 
        message: '增量扫描已完成',
        type: 'incremental'
      });
    } else {
      res.status(400).json({ error: '无效的扫描类型，支持 full 或 incremental' });
    }
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// 获取扫描状态
app.get('/api/downloads/scan-status', async (req, res) => {
  try {
    const status = downloader.getScanStatus();
    res.json(status);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// 清理数据库中不存在的文件记录
app.post('/api/downloads/cleanup-db', async (req, res) => {
  try {
    const result = await downloader.cleanupDatabase();
    res.json({
      success: true,
      message: '数据库清理完成',
      ...result
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// YouTube 搜索 API
app.post('/api/search', async (req, res) => {
  try {
    const { 
      query, 
      maxResults = 20, 
      sortBy = 'relevance',
      searchType = 'keyword',
      videoType = 'all'
    } = req.body;
    
    if (!query || query.trim() === '') {
      return res.status(400).json({ error: '请提供搜索关键字' });
    }

    // 构建搜索查询
    let searchQuery = query.trim();
    let searchUrl;
    
    // 处理标签搜索
    if (searchType === 'hashtag') {
      // 移除用户输入的#号（如果有）
      const hashtag = searchQuery.replace(/^#/, '');
      
      // 如果是短视频，使用特定的hashtag shorts URL
      if (videoType === 'shorts') {
        // 对标签进行URL编码，确保非英文字符正确处理
        const encodedHashtag = encodeURIComponent(hashtag);
        searchUrl = `https://www.youtube.com/hashtag/${encodedHashtag}/shorts`;
        console.log('使用标签短视频搜索URL:', searchUrl);
        console.log('原始标签:', hashtag, '编码后:', encodedHashtag);
      } else {
        // 普通标签搜索
        searchQuery = '#' + hashtag;
        searchUrl = `ytsearch${maxResults}:${searchQuery}`;
      }
    } else {
      // 关键字搜索
      if (videoType === 'shorts') {
        searchQuery += ' shorts';
      }
      searchUrl = `ytsearch${maxResults}:${searchQuery}`;
    }

    // 构建yt-dlp参数
    const args = [
      searchUrl,
      '--dump-json',
      '--flat-playlist',
      '--no-warnings'
    ];

    // 根据排序方式调整搜索
    if (sortBy === 'upload_date') {
      args.push('--playlist-reverse');
    } else if (sortBy === 'view_count') {
      // yt-dlp 默认按相关性排序，view_count 需要额外处理
      args.push('--extractor-args', 'youtube:sort=view_count');
    }

    console.log('执行搜索命令:', 'yt-dlp', args.join(' '));
    console.log('搜索参数:', { searchType, videoType, originalQuery: query, finalQuery: searchQuery });

    const { spawn } = require('child_process');
    const ytDlpProcess = spawn('yt-dlp', args);
    
    let output = '';
    let errorOutput = '';

    ytDlpProcess.stdout.on('data', (data) => {
      output += data.toString();
    });

    ytDlpProcess.stderr.on('data', (data) => {
      errorOutput += data.toString();
    });

    ytDlpProcess.on('close', (code) => {
      if (code !== 0) {
        console.error('搜索失败:', errorOutput);
        return res.status(500).json({ error: '搜索失败: ' + errorOutput });
      }

      try {
        // 解析 JSON 输出
        const lines = output.trim().split('\n').filter(line => line.trim());
        let videos = [];

        for (const line of lines) {
          try {
            const videoData = JSON.parse(line);
            if (videoData.id && videoData.title) {
              const video = {
                id: videoData.id,
                title: videoData.title,
                url: videoData.url || `https://www.youtube.com/watch?v=${videoData.id}`,
                thumbnail: videoData.thumbnail || `https://img.youtube.com/vi/${videoData.id}/mqdefault.jpg`,
                duration: videoData.duration || null,
                uploader: videoData.uploader || videoData.channel || '未知',
                view_count: videoData.view_count || null,
                upload_date: videoData.upload_date || null,
                description: videoData.description || ''
              };
              
              videos.push(video);
            }
          } catch (parseError) {
            console.warn('解析视频数据失败:', parseError.message);
          }
        }

        // 根据视频类型进行后过滤
        if (videoType === 'shorts') {
          // 过滤短视频（通常时长小于60秒）
          videos = videos.filter(video => {
            return video.duration && video.duration <= 60;
          });
        } else if (videoType === 'long') {
          // 过滤长视频（时长大于60秒）
          videos = videos.filter(video => {
            return !video.duration || video.duration > 60;
          });
        }

        console.log(`搜索完成: 找到 ${videos.length} 个视频 (类型: ${videoType})`);

        res.json({
          success: true,
          query: searchQuery,
          originalQuery: query,
          searchType,
          videoType,
          results: videos,
          total: videos.length
        });

      } catch (error) {
        console.error('处理搜索结果失败:', error);
        res.status(500).json({ error: '处理搜索结果失败: ' + error.message });
      }
    });

  } catch (error) {
    console.error('搜索错误:', error);
    res.status(500).json({ error: error.message });
  }
});

// 视频处理 API
app.post('/api/video/process', upload.any(), async (req, res) => {
  try {
    let videoFiles, operations, outputDir, serialProcessing = false;
    
    // 检查是否是FormData请求（包含文件上传）
    if (req.files && req.files.length > 0) {
      // 处理FormData请求
      videoFiles = JSON.parse(req.body.videoFiles || '[]');
      operations = JSON.parse(req.body.operations || '[]');
      outputDir = req.body.outputDir;
      serialProcessing = req.body.serialProcessing === 'true';
      
      // 处理上传的文件，将文件路径映射到operations中
      const fileMap = {};
      req.files.forEach(file => {
        fileMap[file.fieldname] = file.path;
      });
      
      // 更新operations中的文件路径
      operations = operations.map(operation => {
        if (operation.params && operation.params.subtitleFile && fileMap[operation.params.subtitleFile]) {
          operation.params.subtitleFile = fileMap[operation.params.subtitleFile];
        }
        return operation;
      });
    } else {
      // 处理普通JSON请求
      ({ videoFiles, operations, outputDir, serialProcessing = false } = req.body);
    }
    
    // 验证输入
    if (!videoFiles || !Array.isArray(videoFiles) || videoFiles.length === 0) {
      return res.status(400).json({ error: '请提供有效的视频文件列表' });
    }
    
    if (!operations || !Array.isArray(operations) || operations.length === 0) {
      return res.status(400).json({ error: '请提供有效的操作列表' });
    }

    // 使用默认输出目录或指定目录
    const processOutputDir = outputDir || path.join(downloadDir, 'processed');
    await fs.ensureDir(processOutputDir);

    // 创建工作流
    const workflowId = await videoProcessor.createWorkflow(videoFiles, operations, processOutputDir);
    
    const processingMode = serialProcessing ? '串行处理' : '并行处理';
    res.json({ 
      success: true, 
      workflowId,
      serialProcessing,
      message: `视频${processingMode}工作流已创建，正在处理中...` 
    });

    // 异步执行工作流
    videoProcessor.executeWorkflow(workflowId, (progress) => {
      // 通过Socket.IO发送进度更新
      if (progress.status === 'completed') {
        // 获取输出文件的详细信息
        let fileSize = 0;
        let duration = 0;
        
        if (progress.finalOutputs && progress.finalOutputs.length > 0) {
          try {
            const outputPath = progress.finalOutputs[0];
            if (fs.existsSync(outputPath)) {
              const stats = fs.statSync(outputPath);
              fileSize = stats.size;
              
              // 尝试获取视频时长（这里可以使用ffprobe，但为了简化先设为0）
              // 在实际应用中，可以使用ffprobe来获取视频时长
            }
          } catch (error) {
            console.error('获取文件信息失败:', error);
          }
        }
        
        // 获取工作流详情
        const workflowDetails = videoProcessor.getWorkflowDetails(workflowId);
        
        io.emit('video-process-complete', {
          workflowId,
          outputPath: progress.finalOutputs ? progress.finalOutputs.join(', ') : '',
          message: progress.message || '处理完成!',
          serialProcessing,
          fileSize,
          duration,
          workflow: workflowDetails
        });
      } else if (progress.status === 'failed') {
        io.emit('video-process-error', {
          workflowId,
          error: progress.error,
          serialProcessing
        });
      } else {
        io.emit('video-process-progress', {
          workflowId,
          serialProcessing,
          ...progress
        });
      }
    }, serialProcessing).catch(error => {
      io.emit('video-process-error', {
        workflowId,
        error: error.message,
        serialProcessing
      });
    });

  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.get('/api/video/process/:workflowId/status', async (req, res) => {
  try {
    const { workflowId } = req.params;
    const status = videoProcessor.getWorkflowStatus(workflowId);
    const details = videoProcessor.getWorkflowDetails(workflowId);
    
    res.json({ 
      status,
      details: details ? {
        id: details.id,
        status: details.status,
        currentStep: details.currentStep,
        totalSteps: details.operations.length,
        finalOutputs: details.finalOutputs,
        createdAt: details.createdAt
      } : null
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.get('/api/video/process/:workflowId/details', async (req, res) => {
  try {
    const { workflowId } = req.params;
    const details = videoProcessor.getWorkflowDetails(workflowId);
    
    if (!details) {
      return res.status(404).json({ error: '工作流不存在' });
    }
    
    res.json(details);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.delete('/api/video/process/:workflowId/cleanup', async (req, res) => {
  try {
    const { workflowId } = req.params;
    await videoProcessor.cleanupWorkflow(workflowId);
    res.json({ success: true, message: '工作流清理完成' });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// 产出物管理 API
app.post('/api/delete-output', async (req, res) => {
  try {
    const { filepath } = req.body;
    
    if (!filepath) {
      return res.status(400).json({ error: '缺少文件路径参数' });
    }
    
    // 检查文件是否存在
    if (!fs.existsSync(filepath)) {
      return res.status(404).json({ error: '文件不存在' });
    }
    
    // 删除文件
    fs.unlinkSync(filepath);
    
    res.json({ success: true, message: '文件删除成功' });
  } catch (error) {
    console.error('删除产出物失败:', error);
    res.status(500).json({ error: '删除文件失败: ' + error.message });
  }
});

// 删除下载文件 API
app.post('/api/delete-download-file', async (req, res) => {
  try {
    const { filepath } = req.body;
    
    if (!filepath) {
      return res.status(400).json({ error: '缺少文件路径参数' });
    }
    
    // 构建完整的文件路径
    const downloadsDir = path.join(__dirname, '..', 'downloads');
    const fullPath = path.join(downloadsDir, filepath);
    
    // 安全检查：确保文件路径在downloads目录内
    if (!fullPath.startsWith(downloadsDir)) {
      return res.status(400).json({ error: '无效的文件路径' });
    }
    
    // 检查文件是否存在
    if (!fs.existsSync(fullPath)) {
      return res.status(404).json({ error: '文件不存在' });
    }
    
    // 删除文件
    fs.unlinkSync(fullPath);
    
    res.json({ success: true, message: '文件删除成功' });
  } catch (error) {
    console.error('删除下载文件失败:', error);
    res.status(500).json({ error: '删除文件失败: ' + error.message });
  }
});

// 删除下载文件夹 API
app.post('/api/delete-download-folder', async (req, res) => {
  try {
    const { folderpath } = req.body;
    
    if (!folderpath) {
      return res.status(400).json({ error: '缺少文件夹路径参数' });
    }
    
    // 构建完整的文件夹路径
    const downloadsDir = path.join(__dirname, '..', 'downloads');
    const fullPath = path.join(downloadsDir, folderpath);
    
    // 安全检查：确保文件夹路径在downloads目录内
    if (!fullPath.startsWith(downloadsDir)) {
      return res.status(400).json({ error: '无效的文件夹路径' });
    }
    
    // 检查文件夹是否存在
    if (!fs.existsSync(fullPath)) {
      return res.status(404).json({ error: '文件夹不存在' });
    }
    
    // 检查是否为目录
    if (!fs.lstatSync(fullPath).isDirectory()) {
      return res.status(400).json({ error: '指定路径不是文件夹' });
    }
    
    // 递归删除文件夹及其内容
    const deleteRecursive = (dirPath) => {
      if (fs.existsSync(dirPath)) {
        fs.readdirSync(dirPath).forEach((file) => {
          const curPath = path.join(dirPath, file);
          if (fs.lstatSync(curPath).isDirectory()) {
            deleteRecursive(curPath);
          } else {
            fs.unlinkSync(curPath);
          }
        });
        fs.rmdirSync(dirPath);
      }
    };
    
    deleteRecursive(fullPath);
    
    res.json({ success: true, message: '文件夹删除成功' });
  } catch (error) {
    console.error('删除下载文件夹失败:', error);
    res.status(500).json({ error: '删除文件夹失败: ' + error.message });
  }
});

app.post('/api/clear-outputs', async (req, res) => {
  try {
    const outputDir = path.join(__dirname, '..', 'outputs');
    console.log('开始清空产出物，目录路径:', outputDir);
    
    if (!fs.existsSync(outputDir)) {
      console.log('输出目录不存在，无需清空');
      return res.json({ success: true, message: '输出目录不存在，无需清空' });
    }
    
    let deletedFiles = 0;
    let deletedDirs = 0;
    let errors = [];
    
    // 递归删除输出目录中的所有文件
    const deleteRecursive = (dirPath) => {
      if (fs.existsSync(dirPath)) {
        try {
          const files = fs.readdirSync(dirPath);
          files.forEach((file) => {
            const curPath = path.join(dirPath, file);
            try {
              const stats = fs.lstatSync(curPath);
              if (stats.isDirectory()) {
                deleteRecursive(curPath);
              } else {
                fs.unlinkSync(curPath);
                deletedFiles++;
                console.log('已删除文件:', curPath);
              }
            } catch (fileError) {
              console.error('删除文件失败:', curPath, fileError.message);
              errors.push(`删除文件失败: ${curPath} - ${fileError.message}`);
            }
          });
          
          // 删除空目录（但保留outputs根目录）
          if (dirPath !== outputDir) {
            try {
              fs.rmdirSync(dirPath);
              deletedDirs++;
              console.log('已删除目录:', dirPath);
            } catch (dirError) {
              console.error('删除目录失败:', dirPath, dirError.message);
              errors.push(`删除目录失败: ${dirPath} - ${dirError.message}`);
            }
          }
        } catch (readError) {
          console.error('读取目录失败:', dirPath, readError.message);
          errors.push(`读取目录失败: ${dirPath} - ${readError.message}`);
        }
      }
    };
    
    // 只删除文件，保留outputs目录结构
    try {
      const rootFiles = fs.readdirSync(outputDir);
      rootFiles.forEach((file) => {
        const curPath = path.join(outputDir, file);
        try {
          const stats = fs.lstatSync(curPath);
          if (stats.isDirectory()) {
            deleteRecursive(curPath);
            try {
              fs.rmdirSync(curPath);
              deletedDirs++;
              console.log('已删除根目录:', curPath);
            } catch (dirError) {
              console.error('删除根目录失败:', curPath, dirError.message);
              errors.push(`删除根目录失败: ${curPath} - ${dirError.message}`);
            }
          } else {
            fs.unlinkSync(curPath);
            deletedFiles++;
            console.log('已删除根文件:', curPath);
          }
        } catch (fileError) {
          console.error('处理根文件失败:', curPath, fileError.message);
          errors.push(`处理根文件失败: ${curPath} - ${fileError.message}`);
        }
      });
    } catch (rootError) {
      console.error('读取根目录失败:', outputDir, rootError.message);
      errors.push(`读取根目录失败: ${outputDir} - ${rootError.message}`);
    }
    
    const message = `清空完成: 删除了 ${deletedFiles} 个文件和 ${deletedDirs} 个目录`;
    console.log(message);
    
    if (errors.length > 0) {
      console.warn('清空过程中出现错误:', errors);
      res.json({ 
        success: true, 
        message: message,
        warnings: errors,
        deletedFiles,
        deletedDirs
      });
    } else {
      res.json({ 
        success: true, 
        message: message,
        deletedFiles,
        deletedDirs
      });
    }
  } catch (error) {
    console.error('清空产出物失败:', error);
    res.status(500).json({ error: '清空产出物失败: ' + error.message });
  }
});

// 获取视频信息
app.post('/api/video-info', async (req, res) => {
  try {
    const { filePath } = req.body;
    
    if (!filePath) {
      return res.status(400).json({ error: '缺少文件路径参数' });
    }
    
    // 使用VideoInfoHelper获取扩展的视频信息
    const VideoInfoHelper = require('./videoInfoHelper');
    const videoInfoHelper = new VideoInfoHelper(path.join(__dirname, '..', 'downloads'));
    const videoInfo = await videoInfoHelper.getVideoInfo(filePath);
    
    res.json(videoInfo);
  } catch (error) {
    console.error('获取视频信息失败:', error);
    res.status(500).json({ error: '获取视频信息失败: ' + error.message });
  }
});

// 文件清理预览 API
app.post('/api/cleanup-preview', async (req, res) => {
  try {
    const { type, date } = req.body;
    
    if (!type || !date) {
      return res.status(400).json({ error: '缺少必要参数' });
    }
    
    const targetDate = new Date(date);
    const files = [];
    let totalSize = 0;
    
    if (type === 'downloads') {
      // 预览下载文件
      const downloadsDir = path.join(__dirname, '..', 'downloads');
      if (fs.existsSync(downloadsDir)) {
        const scanDirectory = (dirPath, relativePath = '') => {
          const items = fs.readdirSync(dirPath);
          
          for (const item of items) {
            const fullPath = path.join(dirPath, item);
            const itemRelativePath = path.join(relativePath, item);
            const stats = fs.statSync(fullPath);
            
            if (stats.isDirectory()) {
              scanDirectory(fullPath, itemRelativePath);
            } else {
              // 检查文件修改时间
              if (stats.mtime < targetDate) {
                files.push({
                  path: itemRelativePath,
                  size: stats.size,
                  mtime: stats.mtime,
                  type: 'file'
                });
                totalSize += stats.size;
              }
            }
          }
        };
        
        scanDirectory(downloadsDir);
      }
    } else if (type === 'outputs') {
      // 预览产出物文件
      const outputsDir = path.join(__dirname, '..', 'outputs');
      if (fs.existsSync(outputsDir)) {
        const scanDirectory = (dirPath, relativePath = '') => {
          const items = fs.readdirSync(dirPath);
          
          for (const item of items) {
            const fullPath = path.join(dirPath, item);
            const itemRelativePath = path.join(relativePath, item);
            const stats = fs.statSync(fullPath);
            
            if (stats.isDirectory()) {
              scanDirectory(fullPath, itemRelativePath);
            } else {
              // 检查文件修改时间
              if (stats.mtime < targetDate) {
                files.push({
                  path: itemRelativePath,
                  size: stats.size,
                  mtime: stats.mtime,
                  type: 'file'
                });
                totalSize += stats.size;
              }
            }
          }
        };
        
        scanDirectory(outputsDir);
      }
    }
    
    res.json({
      success: true,
      files: files.sort((a, b) => b.mtime - a.mtime), // 按时间倒序排列
      totalSize,
      fileCount: files.length
    });
  } catch (error) {
    console.error('文件清理预览失败:', error);
    res.status(500).json({ error: '文件清理预览失败: ' + error.message });
  }
});

// 文件清理执行 API
app.post('/api/cleanup-execute', async (req, res) => {
  try {
    const { type, date } = req.body;
    
    if (!type || !date) {
      return res.status(400).json({ error: '缺少必要参数' });
    }
    
    const targetDate = new Date(date);
    const deletedFiles = [];
    const deletedFolders = [];
    let totalSize = 0;
    
    const deleteRecursive = (dirPath) => {
      if (fs.existsSync(dirPath)) {
        const items = fs.readdirSync(dirPath);
        for (const item of items) {
          const curPath = path.join(dirPath, item);
          const stats = fs.statSync(curPath);
          
          if (stats.isDirectory()) {
            deleteRecursive(curPath);
            // 检查目录是否为空，如果为空则删除
            try {
              const remainingItems = fs.readdirSync(curPath);
              if (remainingItems.length === 0) {
                fs.rmdirSync(curPath);
                deletedFolders.push(curPath);
              }
            } catch (e) {
              // 目录可能已被删除
            }
          } else {
            // 检查文件修改时间
            if (stats.mtime < targetDate) {
              totalSize += stats.size;
              fs.unlinkSync(curPath);
              deletedFiles.push(curPath);
            }
          }
        }
      }
    };
    
    if (type === 'downloads') {
      // 清理下载文件
      const downloadsDir = path.join(__dirname, '..', 'downloads');
      if (fs.existsSync(downloadsDir)) {
        deleteRecursive(downloadsDir);
      }
    } else if (type === 'outputs') {
      // 清理产出物文件
      const outputsDir = path.join(__dirname, '..', 'outputs');
      if (fs.existsSync(outputsDir)) {
        deleteRecursive(outputsDir);
      }
    }
    
    res.json({
      success: true,
      message: `文件清理完成，删除了 ${deletedFiles.length} 个文件和 ${deletedFolders.length} 个空文件夹`,
      deletedFiles: deletedFiles.length,
      deletedFolders: deletedFolders.length,
      totalSize
    });
  } catch (error) {
    console.error('文件清理执行失败:', error);
    res.status(500).json({ error: '文件清理执行失败: ' + error.message });
  }
});

// 生成视频预览图
app.post('/api/video-preview', async (req, res) => {
  try {
    const { filePath, timestamp = 10, width = 640, height = 360 } = req.body;
    
    if (!filePath) {
      return res.status(400).json({ error: '缺少文件路径参数' });
    }
    
    const previewPath = await videoProcessor.generateVideoPreview(filePath, { timestamp, width, height });
    
    // 返回预览图的相对路径，用于前端访问
    const relativePath = path.relative(path.join(__dirname, '..'), previewPath);
    res.json({ 
      success: true, 
      previewPath: relativePath.replace(/\\/g, '/') // 统一使用正斜杠
    });
  } catch (error) {
    console.error('生成视频预览失败:', error);
    res.status(500).json({ error: '生成视频预览失败: ' + error.message });
  }
});

// 背景图管理 API
// 获取所有背景图列表
app.get('/api/backgrounds', async (req, res) => {
  try {
    const uploadsDir = path.join(__dirname, '../uploads');
    
    if (!fs.existsSync(uploadsDir)) {
      return res.json({ backgrounds: [], totalCount: 0, totalSize: 0 });
    }

    const files = await fs.readdir(uploadsDir);
    const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'];
    
    // 过滤出图片文件并获取详细信息
    const backgrounds = [];
    let totalSize = 0;
    
    for (const file of files) {
      const ext = path.extname(file).toLowerCase();
      if (imageExtensions.includes(ext)) {
        const filePath = path.join(uploadsDir, file);
        try {
          const stats = await fs.stat(filePath);
          const background = {
            name: file,
            path: `/uploads/${file}`,
            size: stats.size,
            sizeFormatted: formatFileSize(stats.size),
            createdAt: stats.birthtime,
            modifiedAt: stats.mtime,
            extension: ext,
            type: 'image'
          };
          backgrounds.push(background);
          totalSize += stats.size;
        } catch (error) {
          console.error(`获取文件信息失败: ${file}`, error);
        }
      }
    }

    // 按修改时间倒序排列
    backgrounds.sort((a, b) => new Date(b.modifiedAt) - new Date(a.modifiedAt));

    res.json({
      backgrounds,
      totalCount: backgrounds.length,
      totalSize,
      totalSizeFormatted: formatFileSize(totalSize)
    });
  } catch (error) {
    console.error('获取背景图列表失败:', error);
    res.status(500).json({ error: '获取背景图列表失败: ' + error.message });
  }
});

// 删除单个背景图
app.post('/api/delete-background', async (req, res) => {
  try {
    const { filename } = req.body;
    
    if (!filename) {
      return res.status(400).json({ error: '缺少文件名参数' });
    }

    const uploadsDir = path.join(__dirname, '../uploads');
    const filePath = path.join(uploadsDir, filename);
    
    // 安全检查：确保文件路径在uploads目录内
    if (!filePath.startsWith(uploadsDir)) {
      return res.status(400).json({ error: '无效的文件路径' });
    }

    if (!fs.existsSync(filePath)) {
      return res.status(404).json({ error: '文件不存在' });
    }

    await fs.unlink(filePath);
    console.log(`背景图删除成功: ${filename}`);
    
    res.json({ success: true, message: '背景图删除成功' });
  } catch (error) {
    console.error('删除背景图失败:', error);
    res.status(500).json({ error: '删除背景图失败: ' + error.message });
  }
});

// 删除所有背景图
app.post('/api/delete-all-backgrounds', async (req, res) => {
  try {
    const uploadsDir = path.join(__dirname, '../uploads');
    
    if (!fs.existsSync(uploadsDir)) {
      return res.json({ success: true, message: '背景图目录不存在，无需清理' });
    }

    const files = await fs.readdir(uploadsDir);
    const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'];
    
    let deletedCount = 0;
    let totalSize = 0;

    for (const file of files) {
      const ext = path.extname(file).toLowerCase();
      if (imageExtensions.includes(ext)) {
        const filePath = path.join(uploadsDir, file);
        try {
          const stats = await fs.stat(filePath);
          totalSize += stats.size;
          await fs.unlink(filePath);
          deletedCount++;
          console.log(`背景图删除成功: ${file}`);
        } catch (error) {
          console.error(`删除背景图失败: ${file}`, error);
        }
      }
    }

    res.json({ 
      success: true, 
      message: `成功删除 ${deletedCount} 个背景图文件`,
      deletedCount,
      totalSizeFreed: formatFileSize(totalSize)
    });
  } catch (error) {
    console.error('删除所有背景图失败:', error);
    res.status(500).json({ error: '删除所有背景图失败: ' + error.message });
  }
});

// ==================== 记录链接功能 API ====================

// 保存链接数据文件路径
const savedLinksFile = path.join(__dirname, '../data/saved-links.json');

// 确保数据目录存在
const dataDir = path.dirname(savedLinksFile);
if (!fs.existsSync(dataDir)) {
  fs.mkdirSync(dataDir, { recursive: true });
}

// 读取保存的链接
function readSavedLinks() {
  try {
    if (fs.existsSync(savedLinksFile)) {
      const data = fs.readFileSync(savedLinksFile, 'utf8');
      return JSON.parse(data);
    }
    return { links: [], tags: [] };
  } catch (error) {
    console.error('读取保存的链接失败:', error);
    return { links: [], tags: [] };
  }
}

// 写入保存的链接
function writeSavedLinks(data) {
  try {
    fs.writeFileSync(savedLinksFile, JSON.stringify(data, null, 2), 'utf8');
    return true;
  } catch (error) {
    console.error('写入保存的链接失败:', error);
    return false;
  }
}

// 从YouTube URL中提取视频ID（复用downloader中的逻辑）
function extractVideoId(url) {
  try {
    const urlObj = new URL(url);
    
    // 处理标准YouTube URL: https://www.youtube.com/watch?v=VIDEO_ID
    if (urlObj.hostname.includes('youtube.com') && urlObj.pathname === '/watch') {
      const videoId = urlObj.searchParams.get('v');
      if (videoId) return videoId;
    }
    
    // 处理YouTube Shorts URL: https://www.youtube.com/shorts/VIDEO_ID
    if (urlObj.hostname.includes('youtube.com') && urlObj.pathname.startsWith('/shorts/')) {
      const videoId = urlObj.pathname.split('/shorts/')[1];
      if (videoId) return videoId;
    }
    
    // 处理短链接: https://youtu.be/VIDEO_ID
    if (urlObj.hostname === 'youtu.be') {
      const videoId = urlObj.pathname.substring(1); // 移除开头的 '/'
      if (videoId) return videoId;
    }
    
    // 如果无法提取，返回null
    return null;
  } catch (error) {
    console.warn('提取视频ID失败:', error.message);
    return null;
  }
}

// 删除已完成下载的链接
async function removeCompletedLinkFromSaved(downloadedUrl) {
  try {
    console.log('尝试删除已完成的链接:', downloadedUrl);
    
    const savedData = readSavedLinks();
    if (!savedData.links || savedData.links.length === 0) {
      console.log('没有保存的链接需要删除');
      return;
    }
    
    const downloadedVideoId = extractVideoId(downloadedUrl);
    if (!downloadedVideoId) {
      console.warn('无法从下载URL中提取视频ID:', downloadedUrl);
      return;
    }
    
    const originalCount = savedData.links.length;
    
    // 查找并删除匹配的链接
    savedData.links = savedData.links.filter(link => {
      const linkVideoId = extractVideoId(link.url);
      const shouldKeep = linkVideoId !== downloadedVideoId;
      
      if (!shouldKeep) {
        console.log(`找到匹配的链接并删除: ${link.title || link.url}`);
      }
      
      return shouldKeep;
    });
    
    const deletedCount = originalCount - savedData.links.length;
    
    if (deletedCount > 0) {
      // 更新文件
      writeSavedLinks(savedData);
      console.log(`成功删除 ${deletedCount} 个已完成的链接`);
      
      // 通知所有连接的客户端链接已被删除
      io.emit('link-deleted', {
        videoId: downloadedVideoId,
        deletedCount,
        remainingCount: savedData.links.length
      });
    } else {
      console.log('未找到匹配的链接需要删除');
    }
    
  } catch (error) {
    console.error('删除已完成链接时出错:', error.message);
    throw error;
  }
}

// 获取视频信息（用于保存链接时获取元数据）
async function getVideoMetadata(url) {
  try {
    const videoInfo = await downloader.getVideoInfo(url);
    return {
      title: videoInfo.title || '未知标题',
      channel: videoInfo.uploader || videoInfo.channel || '未知频道',
      duration: videoInfo.duration_string || null,
      viewCount: videoInfo.view_count ? formatViewCount(videoInfo.view_count) : null,
      thumbnail: videoInfo.thumbnail || null
    };
  } catch (error) {
    console.error('获取视频信息失败:', error);
    return {
      title: '未知标题',
      channel: '未知频道',
      duration: null,
      viewCount: null,
      thumbnail: null
    };
  }
}

// 格式化观看次数
function formatViewCount(count) {
  if (count >= 1000000) {
    return (count / 1000000).toFixed(1) + 'M';
  } else if (count >= 1000) {
    return (count / 1000).toFixed(1) + 'K';
  }
  return count.toString();
}

// 异步获取视频元数据的队列
const metadataQueue = [];
let isProcessingMetadata = false;

// 批量处理视频元数据
async function processMetadataQueue() {
  if (isProcessingMetadata || metadataQueue.length === 0) {
    return;
  }

  isProcessingMetadata = true;
  console.log(`开始处理视频元数据队列，共 ${metadataQueue.length} 个链接`);

  // 分批处理，每批5个
  const batchSize = 5;
  while (metadataQueue.length > 0) {
    const batch = metadataQueue.splice(0, batchSize);
    
    // 并行处理当前批次
    const promises = batch.map(async (item) => {
      try {
        console.log(`获取视频元数据: ${item.url}`);
        const metadata = await getVideoMetadata(item.url);
        
        // 更新保存的链接数据
        const savedData = readSavedLinks();
        const linkIndex = savedData.links.findIndex(link => link.id === item.id);
        
        if (linkIndex !== -1) {
          savedData.links[linkIndex] = {
            ...savedData.links[linkIndex],
            title: metadata.title,
            channel: metadata.channel,
            duration: metadata.duration,
            viewCount: metadata.viewCount,
            thumbnail: metadata.thumbnail,
            metadataUpdated: true,
            metadataUpdatedAt: new Date().toISOString()
          };
          
          writeSavedLinks(savedData);
          console.log(`已更新视频元数据: ${metadata.title}`);
        }
      } catch (error) {
        console.error(`获取视频元数据失败 ${item.url}:`, error);
        
        // 标记为获取失败
        const savedData = readSavedLinks();
        const linkIndex = savedData.links.findIndex(link => link.id === item.id);
        
        if (linkIndex !== -1) {
          savedData.links[linkIndex] = {
            ...savedData.links[linkIndex],
            metadataUpdated: true,
            metadataError: true,
            metadataUpdatedAt: new Date().toISOString()
          };
          
          writeSavedLinks(savedData);
        }
      }
    });

    await Promise.all(promises);
    
    // 批次间稍作延迟，避免过于频繁的请求
    if (metadataQueue.length > 0) {
      await new Promise(resolve => setTimeout(resolve, 2000));
    }
  }

  isProcessingMetadata = false;
  console.log('视频元数据队列处理完成');
}

// 保存链接（优化版本）
app.post('/api/save-links', async (req, res) => {
  try {
    const { urls, tag } = req.body;

    if (!urls || !Array.isArray(urls) || urls.length === 0) {
      return res.status(400).json({ success: false, error: '请提供有效的链接列表' });
    }

    if (!tag || typeof tag !== 'string' || tag.trim() === '') {
      return res.status(400).json({ success: false, error: '请提供有效的标签' });
    }

    const savedData = readSavedLinks();
    let savedCount = 0;
    const newLinks = [];

    for (const url of urls) {
      // 检查链接是否已存在
      const existingLink = savedData.links.find(link => link.url === url);
      if (existingLink) {
        console.log(`链接已存在，跳过: ${url}`);
        continue;
      }

      // 创建新的链接记录（仅包含基本信息）
      const newLink = {
        id: Date.now() + Math.random(),
        url: url,
        tag: tag.trim(),
        title: '正在获取...',
        channel: '正在获取...',
        duration: null,
        viewCount: null,
        thumbnail: null,
        metadataUpdated: false,
        savedAt: new Date().toISOString()
      };

      savedData.links.push(newLink);
      newLinks.push(newLink);
      savedCount++;
    }

    // 更新标签列表
    if (!savedData.tags.includes(tag.trim())) {
      savedData.tags.push(tag.trim());
      savedData.tags.sort();
    }

    // 保存到文件
    if (writeSavedLinks(savedData)) {
      // 将新链接添加到元数据获取队列
      newLinks.forEach(link => {
        metadataQueue.push({
          id: link.id,
          url: link.url
        });
      });

      // 异步开始处理元数据队列
      setImmediate(() => {
        processMetadataQueue();
      });

      res.json({ 
        success: true, 
        savedCount,
        message: `成功保存 ${savedCount} 个链接，正在后台获取视频信息...`
      });
    } else {
      res.status(500).json({ success: false, error: '保存链接到文件失败' });
    }
  } catch (error) {
    console.error('保存链接失败:', error);
    res.status(500).json({ success: false, error: '保存链接失败: ' + error.message });
  }
});

// 获取保存的链接
app.get('/api/saved-links', async (req, res) => {
  try {
    const savedData = readSavedLinks();
    
    // 按保存时间倒序排列
    savedData.links.sort((a, b) => new Date(b.savedAt) - new Date(a.savedAt));
    
    // 计算元数据更新状态
    const totalLinks = savedData.links.length;
    const updatedLinks = savedData.links.filter(link => link.metadataUpdated).length;
    const pendingLinks = savedData.links.filter(link => !link.metadataUpdated).length;
    
    res.json({ 
      success: true, 
      links: savedData.links,
      tags: savedData.tags,
      metadataStatus: {
        total: totalLinks,
        updated: updatedLinks,
        pending: pendingLinks,
        isProcessing: isProcessingMetadata,
        queueLength: metadataQueue.length
      }
    });
  } catch (error) {
    console.error('获取保存的链接失败:', error);
    res.status(500).json({ success: false, error: '获取保存的链接失败: ' + error.message });
  }
});

// 获取元数据更新状态
app.get('/api/metadata-status', async (req, res) => {
  try {
    const savedData = readSavedLinks();
    const totalLinks = savedData.links.length;
    const updatedLinks = savedData.links.filter(link => link.metadataUpdated).length;
    const pendingLinks = savedData.links.filter(link => !link.metadataUpdated).length;
    
    res.json({
      success: true,
      status: {
        total: totalLinks,
        updated: updatedLinks,
        pending: pendingLinks,
        isProcessing: isProcessingMetadata,
        queueLength: metadataQueue.length
      }
    });
  } catch (error) {
    console.error('获取元数据状态失败:', error);
    res.status(500).json({ success: false, error: '获取元数据状态失败: ' + error.message });
  }
});

// 删除保存的链接
app.post('/api/delete-saved-links', async (req, res) => {
  try {
    const { linkIds } = req.body;

    if (!linkIds || !Array.isArray(linkIds) || linkIds.length === 0) {
      return res.status(400).json({ success: false, error: '请提供要删除的链接ID列表' });
    }

    const savedData = readSavedLinks();
    const originalCount = savedData.links.length;

    // 删除指定的链接
    savedData.links = savedData.links.filter(link => !linkIds.includes(link.id));
    
    const deletedCount = originalCount - savedData.links.length;

    // 更新标签列表（移除不再使用的标签）
    const usedTags = [...new Set(savedData.links.map(link => link.tag))];
    savedData.tags = savedData.tags.filter(tag => usedTags.includes(tag));

    // 保存到文件
    if (writeSavedLinks(savedData)) {
      res.json({ 
        success: true, 
        deletedCount,
        message: `成功删除 ${deletedCount} 个链接`
      });
    } else {
      res.status(500).json({ success: false, error: '保存更改到文件失败' });
    }
  } catch (error) {
    console.error('删除保存的链接失败:', error);
    res.status(500).json({ success: false, error: '删除保存的链接失败: ' + error.message });
  }
});

// 辅助函数：格式化文件大小
function formatFileSize(bytes) {
  if (bytes === 0) return '0 B';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

// Socket.IO 连接处理
io.on('connection', (socket) => {
  console.log('用户连接:', socket.id);

  // 检查FFmpeg是否可用
  const checkFFmpegAvailable = () => {
    return new Promise((resolve) => {
      const ffmpeg = spawn('ffmpeg', ['-version']);
      
      ffmpeg.on('error', () => {
        resolve(false);
      });
      
      ffmpeg.on('close', (code) => {
        resolve(code === 0);
      });
    });
  };

  // 重试配置
  const RETRY_CONFIG = {
    maxRetries: 3,
    baseDelay: 2000, // 基础延迟2秒
    maxDelay: 10000, // 最大延迟10秒
    backoffMultiplier: 2 // 指数退避倍数
  };

  // 智能重试函数
  async function downloadWithRetry(downloadData, retryCount = 0) {
    const { url, quality, audioFormat, audioOnly, playlist, subtitles, subtitleLang, saveAsDirectory, batchId, searchContext, presetAlias } = downloadData;
    
    try {
      return await performDownload(downloadData);
    } catch (error) {
      console.error(`下载尝试 ${retryCount + 1} 失败:`, error.message);
      
      if (retryCount < RETRY_CONFIG.maxRetries) {
        // 计算延迟时间（指数退避）
        const delay = Math.min(
          RETRY_CONFIG.baseDelay * Math.pow(RETRY_CONFIG.backoffMultiplier, retryCount),
          RETRY_CONFIG.maxDelay
        );
        
        console.log(`等待 ${delay}ms 后进行第 ${retryCount + 2} 次重试...`);
        
        if (batchId) {
          socket.emit('download-progress', { 
            progress: 0, 
            message: `重试中... (${retryCount + 2}/${RETRY_CONFIG.maxRetries + 1})`,
            batchId 
          });
        } else {
          socket.emit('download-progress', { 
            progress: 0, 
            message: `重试中... (${retryCount + 2}/${RETRY_CONFIG.maxRetries + 1})`
          });
        }
        
        // 等待后重试
        await new Promise(resolve => setTimeout(resolve, delay));
        return await downloadWithRetry(downloadData, retryCount + 1);
      } else {
        // 所有重试都失败，尝试fallback策略
        console.log('所有重试失败，尝试fallback策略...');
        return await tryFallbackStrategies(downloadData);
      }
    }
  }

  // Fallback策略
  async function tryFallbackStrategies(downloadData) {
    const strategies = [
      // 策略1: 使用最基础的参数
      { name: '基础模式', modifyData: (data) => ({ ...data, quality: 'worst', audioOnly: false }) },
      // 策略2: 仅音频模式
      { name: '音频模式', modifyData: (data) => ({ ...data, audioOnly: true, audioFormat: 'mp3' }) },
      // 策略3: 无cookies模式
      { name: '无cookies模式', modifyData: (data) => ({ ...data, noCookies: true }) }
    ];
    
    for (const strategy of strategies) {
      try {
        console.log(`尝试fallback策略: ${strategy.name}`);
        const modifiedData = strategy.modifyData(downloadData);
        
        if (downloadData.batchId) {
          socket.emit('download-progress', { 
            progress: 0, 
            message: `尝试${strategy.name}...`,
            batchId: downloadData.batchId 
          });
        } else {
          socket.emit('download-progress', { 
            progress: 0, 
            message: `尝试${strategy.name}...`
          });
        }
        
        return await performDownload(modifiedData);
      } catch (error) {
        console.error(`Fallback策略 ${strategy.name} 失败:`, error.message);
      }
    }
    
    // 所有策略都失败
    throw new Error('所有下载策略都失败，请检查网络连接或稍后重试');
  }

  // 执行下载的核心函数
  async function performDownload(data) {
    return new Promise(async (resolve, reject) => {
      try {
        const { url, quality, audioFormat, audioOnly, playlist, subtitles, subtitleLang, saveAsDirectory, batchId, searchContext, presetAlias, noCookies } = data;
      
      // URL参数验证
      if (!url || typeof url !== 'string') {
        const error = 'URL参数无效或缺失';
        if (batchId) {
          socket.emit('download-error', { error, batchId });
        } else {
          socket.emit('download-error', { error });
        }
        return;
      }
      
      // 去除前后空格
      const trimmedUrl = url.trim();
      
      // 检查URL格式
      try {
        new URL(trimmedUrl);
      } catch (urlError) {
        const error = '无效的URL格式';
        if (batchId) {
          socket.emit('download-error', { error, batchId });
        } else {
          socket.emit('download-error', { error });
        }
        return;
      }
      
      // 检查是否为支持的视频平台
      const supportedDomains = [
        'youtube.com', 'youtu.be', 'm.youtube.com',
        'bilibili.com', 'b23.tv', 'm.bilibili.com'
      ];
      
      const isSupported = supportedDomains.some(domain => 
        trimmedUrl.includes(domain)
      );
      
      if (!isSupported) {
        const error = '不支持的视频平台，仅支持 YouTube 和 Bilibili';
        if (batchId) {
          socket.emit('download-error', { error, batchId });
        } else {
          socket.emit('download-error', { error });
        }
        return;
      }
      
      // 检查FFmpeg是否可用
      const ffmpegAvailable = await checkFFmpegAvailable();
      
      // 获取视频信息
      const videoInfo = await downloader.getVideoInfo(trimmedUrl, playlist);
      if (!videoInfo || !videoInfo.title) {
        const error = '无法获取视频信息';
        if (batchId) {
          socket.emit('download-error', { error, batchId });
        } else {
          socket.emit('download-error', { error });
        }
        return;
      }

      // 创建下载路径，传递搜索上下文、URL和saveAsDirectory参数
      const downloadPath = downloader.createDownloadPath(videoInfo.title, searchContext, trimmedUrl, saveAsDirectory);
      
      // 检查并删除重复文件（基于视频ID的智能重复检查）
      await downloader.removeExistingFiles(downloadPath, trimmedUrl);
      
      // 构建 yt-dlp 命令
      const args = [trimmedUrl];
      
      // 添加网络重试和超时配置
      args.push('--retries', '10');           // 重试次数
      args.push('--fragment-retries', '10');  // 片段重试次数
      args.push('--socket-timeout', '30');    // Socket超时时间(秒)
      args.push('--user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
      args.push('--sleep-requests', '1');     // 请求间隔时间(秒)
      args.push('--sleep-interval', '0');     // 下载间隔时间(秒)
      args.push('--max-sleep-interval', '5'); // 最大下载间隔时间(秒)
      
      // 智能cookies配置 - 手动cookies文件优先，浏览器fallback策略
      if (!noCookies) {
        let cookiesAdded = false;
        
        // 首先尝试手动cookies文件
        const cookiesFilePath = path.join(__dirname, '..', 'cookies', 'youtube_cookies.txt');
        if (fs.existsSync(cookiesFilePath)) {
          try {
            const cookiesContent = fs.readFileSync(cookiesFilePath, 'utf8').trim();
            if (cookiesContent && !cookiesContent.startsWith('#') && cookiesContent.includes('youtube.com')) {
              args.push('--cookies', cookiesFilePath);
              console.log('✅ 使用手动cookies文件:', cookiesFilePath);
              cookiesAdded = true;
            } else {
              console.warn('⚠️ 手动cookies文件存在但内容无效或为空');
            }
          } catch (error) {
            console.warn('⚠️ 读取手动cookies文件失败:', error.message);
          }
        } else {
          console.log('ℹ️ 未找到手动cookies文件，尝试浏览器cookies');
        }
        
        // 如果手动cookies失败，尝试浏览器cookies（但不实际添加，因为已知会失败）
        if (!cookiesAdded) {
          console.warn('⚠️ 跳过浏览器cookies配置（已知在当前环境下不可用）');
          console.log('💡 建议：请手动导出YouTube cookies到 cookies/youtube_cookies.txt 文件');
          
          // 直接启用无cookies超强绕过模式
          console.log('🚀 启用无cookies超强绕过模式');
        }
      } else {
        console.log('🔧 用户选择无cookies模式，启用超强绕过策略');
      }
      
      // 无cookies模式的超强绕过策略（无论是否有cookies都添加这些参数以增强兼容性）
      args.push('--no-check-certificate');
      args.push('--ignore-config');
      args.push('--no-cache-dir');
      args.push('--no-call-home');
      args.push('--no-check-formats');
      
      // 新增超强YouTube绕过策略
      args.push('--extractor-retries', '10');        // 提取器重试10次
      args.push('--fragment-retries', '10');         // 片段重试10次
      args.push('--retry-sleep', '5');               // 重试间隔5秒
      args.push('--skip-unavailable-fragments');     // 跳过不可用片段
      args.push('--abort-on-unavailable-fragment', 'false'); // 不因片段失败而终止
      
      // 添加更多网络优化参数
      args.push('--http-chunk-size', '10M');  // HTTP块大小，减少网络请求次数
      args.push('--hls-prefer-native');       // 优先使用原生HLS下载器
      args.push('--abort-on-unavailable-fragment'); // 不因单个片段失败而终止下载
      args.push('--keep-fragments');          // 保留片段文件用于调试
      args.push('--concurrent-fragments', '1'); // 限制并发片段下载数量，提高稳定性
      
      // 代理和网络绕过配置 - 增强版
      // 自动地理绕过（无需代理）
      args.push('--geo-bypass');              // 绕过地理限制
      args.push('--geo-bypass-country', 'US'); // 指定绕过国家为美国
      
      // 网络优化和绕过策略
      args.push('--force-ipv4');              // 强制使用IPv4
      args.push('--prefer-insecure');         // 优先使用不安全连接（绕过某些限制）
      args.push('--no-check-certificate');    // 跳过证书验证
      args.push('--ignore-certificate-errors'); // 忽略证书错误
      
      // 高级网络配置
      args.push('--socket-timeout', '60');     // 套接字超时60秒
      args.push('--retries', '10');           // 网络重试10次
      args.push('--file-access-retries', '5'); // 文件访问重试5次
      
      // 如果用户配置了代理，可以在这里添加
      // args.push('--proxy', 'http://proxy-server:port');
      // args.push('--proxy', 'socks5://127.0.0.1:1080'); // SOCKS5代理示例
      
      // 输出模板，包含视频ID以确保唯一性
      const videoId = downloader.extractVideoId(trimmedUrl);
      let outputTemplate;
      if (videoId) {
        outputTemplate = path.join(downloadPath, `%(title)s_${videoId}.%(ext)s`);
      } else {
        outputTemplate = path.join(downloadPath, '%(title)s.%(ext)s');
      }
      args.push('-o', outputTemplate);
      
      // 添加格式优化参数，避免SABR流媒体格式和PO Token问题
      // YouTube增强功能 (yt-dlp 2025.08.20新功能) - 超强验证绕过
      const youtubeArgs = [
        // 多客户端支持 - 使用稳定的web客户端
        'player_client=web,mweb,tv_embedded,android',
        // 格式和令牌处理 - 避免PO Token问题
        'formats=missing_pot',
        'po_token=',  // 禁用PO Token
        'visitor_data=',  // 禁用访客数据
        // API配置 - 使用多个API端点
        'innertube_host=youtubei.googleapis.com,www.youtube.com,m.youtube.com',
        'innertube_key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8,AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w',
        // 验证绕过策略 - 超强模式
        'skip_player_verification=true',
        'bypass_age_gate=true',
        'bypass_geo_restriction=true',
        'bypass_throttling=true',
        'bypass_nsig_throttling=true',  // 绕过N签名限制
        'bypass_po_token=true',         // 绕过PO Token验证
        'bypass_bot_detection=true',    // 绕过机器人检测
        // 播放器配置 - 增强兼容性
        'playback_wait=20',  // 增加等待时间到20秒
        'player_js_variants=es5,es6,base,android,ios',
        'player_skip_initial_js=true',  // 跳过初始JS加载
        'player_cache_dir=',            // 禁用播放器缓存
        // 客户端配置 - 多客户端轮换
        'client_name=WEB,MWEB,ANDROID,IOS',
        'client_version=2.20241201.00.00,2.20241201.01.00',
        'client_screen=EMBED,WATCH,UNIPLAYER',
        // OAuth和认证 - 完全禁用
        'use_oauth=false',
        'include_oauth2_scope=false',
        'oauth2_refresh_token=',
        'oauth2_access_token=',
        // 流媒体配置 - 优化兼容性
        'include_live_dash=false',
        'include_hls_manifest=true',
        'include_dash_manifest=false',
        'prefer_hls=true',
        // 高级绕过选项 - 最大兼容性
        'skip_dash_manifest=true',
        'skip_hls_manifest=false',
        'prefer_legacy_formats=true',
        'legacy_server_connect=true',
        'force_legacy_extractors=true',
        // 机器人检测绕过 - 超强模式
        'comment_sort=top',
        'max_comments=0',
        'include_shorts=false',
        'disable_polymer=true',         // 禁用Polymer界面
        'disable_web_components=true',  // 禁用Web组件
        'simulate_mobile=true',         // 模拟移动设备
        // 网络和请求优化
        'request_timeout=60',           // 请求超时60秒
        'max_retries=10',              // 最大重试10次
        'retry_sleep=3',               // 重试间隔3秒
        'fragment_retries=10',         // 片段重试10次
        // 代理和网络绕过
        'use_proxy_rotation=false',    // 禁用代理轮换（避免复杂性）
        'bypass_cloudflare=true',      // 绕过Cloudflare
        'bypass_rate_limit=true',      // 绕过速率限制
        // 高级反检测
        'randomize_user_agent=true',   // 随机化User-Agent
        'simulate_browser_behavior=true', // 模拟浏览器行为
        'disable_tracking=true',       // 禁用跟踪
        'privacy_mode=true'            // 隐私模式
      ];
      args.push('--extractor-args', `youtube:${youtubeArgs.join(';')}`);
      console.log('已启用YouTube超强验证绕过功能：多客户端、机器人检测绕过、高级API配置');
      // 格式和证书检查优化
       args.push('--no-check-certificate'); // 跳过SSL证书检查，提高兼容性
      
      // 智能User-Agent轮换和高级请求头配置
      const userAgents = [
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0',
        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
      ];
      const randomUA = userAgents[Math.floor(Math.random() * userAgents.length)];
      
      // 高级请求头配置 - 模拟真实浏览器行为
      args.push('--add-header', `User-Agent:${randomUA}`);
      args.push('--add-header', 'Accept-Language:en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7');
      args.push('--add-header', 'Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7');
      args.push('--add-header', 'Accept-Encoding:gzip, deflate, br, zstd');
      args.push('--add-header', 'Cache-Control:max-age=0');
      args.push('--add-header', 'Sec-Ch-Ua:"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"');
      args.push('--add-header', 'Sec-Ch-Ua-Mobile:?0');
      args.push('--add-header', 'Sec-Ch-Ua-Platform:"Windows"');
      args.push('--add-header', 'Sec-Fetch-Dest:document');
      args.push('--add-header', 'Sec-Fetch-Mode:navigate');
      args.push('--add-header', 'Sec-Fetch-Site:none');
      args.push('--add-header', 'Sec-Fetch-User:?1');
      args.push('--add-header', 'Upgrade-Insecure-Requests:1');
      args.push('--add-header', 'Dnt:1');
      args.push('--referer', 'https://www.youtube.com/');
      args.push('--add-header', 'Origin:https://www.youtube.com');
      console.log(`使用随机User-Agent: ${randomUA.substring(0, 50)}...`);
      
      // 超强机器人检测绕过和稳定性参数
      args.push('--no-warnings');
      args.push('--ignore-errors');
      args.push('--no-abort-on-error');
      args.push('--continue-on-error');
      args.push('--skip-unavailable-fragments');
      args.push('--keep-video');
      args.push('--no-overwrites');
      args.push('--age-limit', '99');  // 绕过年龄限制
      args.push('--mark-watched');     // 标记为已观看，模拟正常用户行为
      args.push('--force-json');       // 强制JSON输出
      args.push('--no-check-formats'); // 跳过格式检查
      args.push('--prefer-free-formats'); // 优先选择免费格式
      args.push('--youtube-skip-dash-manifest'); // 跳过DASH清单
      args.push('--youtube-skip-hls-manifest');  // 跳过HLS清单
      args.push('--embed-subs');       // 嵌入字幕而不是单独文件
      args.push('--no-part');          // 不使用.part文件
      args.push('--no-mtime');         // 不设置修改时间
      // 新增超强绕过参数
      args.push('--sleep-requests', '1');     // 请求间隔1秒，模拟人类行为
      args.push('--sleep-subtitles', '0');    // 字幕请求无延迟
      args.push('--max-downloads', '1');      // 限制同时下载数
      args.push('--no-check-certificate');    // 跳过SSL证书验证
      args.push('--no-call-home');           // 不向服务器发送统计信息
      args.push('--geo-bypass');             // 地理位置绕过
      args.push('--geo-bypass-country', 'US'); // 模拟美国IP
      args.push('--socket-timeout', '30');    // 套接字超时30秒
      args.push('--source-address', '0.0.0.0'); // 绑定所有网络接口
      console.log('已启用超强机器人检测绕过和网络优化参数');
      
      // 预设别名支持 (yt-dlp 2025.08.20新功能)
      if (presetAlias && presetAlias !== 'custom') {
        args.push('--preset-alias', presetAlias);
        console.log(`使用预设别名: ${presetAlias}`);
        // 使用预设别名时，跳过传统格式选择以避免冲突
      } else {
        // 质量设置 - 根据FFmpeg可用性选择策略
        if (audioOnly) {
          args.push('-f', `bestaudio[ext=${audioFormat}]/bestaudio`);
          args.push('--extract-audio', '--audio-format', audioFormat);
        } else {
        if (ffmpegAvailable) {
          // FFmpeg可用时，使用最佳的视频+音频组合，避免SABR格式
          if (quality === 'best') {
            args.push('-f', 'bestvideo[ext=mp4][protocol!=http_dash_segments]+bestaudio[ext=m4a]/bestvideo[ext=mp4]+bestaudio[ext=m4a]/bestvideo+bestaudio/best[ext=mp4]/best');
            args.push('--merge-output-format', 'mp4');
          } else if (quality === 'worst') {
            args.push('-f', 'worst[ext=mp4]/worst');
          } else {
            // 对于特定分辨率，避免DASH片段格式
            const resolution = quality.replace('p', '');
            args.push('-f', `bestvideo[height<=${resolution}][ext=mp4][protocol!=http_dash_segments]+bestaudio[ext=m4a]/bestvideo[height<=${resolution}][ext=mp4]+bestaudio[ext=m4a]/best[height<=${resolution}][ext=mp4]/best[height<=${resolution}]`);
            args.push('--merge-output-format', 'mp4');
          }
        } else {
          // FFmpeg不可用时，使用单一格式避免需要合并，避免SABR格式
          console.warn('FFmpeg不可用，使用单一格式下载。建议安装FFmpeg以获得最佳质量。');
          socket.emit('download-progress', { 
            progress: 0, 
            message: 'FFmpeg不可用，使用单一格式下载。建议安装FFmpeg以获得最佳质量。',
            batchId 
          });
          
          if (quality === 'best') {
            args.push('-f', 'best[ext=mp4][protocol!=http_dash_segments]/best[ext=mp4]/best');
          } else if (quality === 'worst') {
            args.push('-f', 'worst[ext=mp4]/worst');
          } else {
            const resolution = quality.replace('p', '');
            args.push('-f', `best[height<=${resolution}][ext=mp4][protocol!=http_dash_segments]/best[height<=${resolution}][ext=mp4]/best[height<=${resolution}]`);
          }
        }
        }
      }
      
      // 播放列表设置
      if (playlist) {
        args.push('--yes-playlist');
      } else {
        args.push('--no-playlist');
      }
      
      // 字幕设置
      if (subtitles) {
        args.push('--write-subs', '--write-auto-subs');
        if (subtitleLang && subtitleLang.trim()) {
          args.push('--sub-lang', subtitleLang);
        } else {
          args.push('--sub-lang', 'zh,en');
        }
      }
      
      // 执行下载
      const ytDlpProcess = spawn('yt-dlp', args);
      
      ytDlpProcess.stdout.on('data', (data) => {
        const output = data.toString();
        console.log('yt-dlp stdout:', output);
        
        // 解析进度
        const progressMatch = output.match(/(\d+(?:\.\d+)?)%/);
        if (progressMatch) {
          const progress = parseFloat(progressMatch[1]);
          if (batchId) {
            socket.emit('download-progress', { progress, batchId });
          } else {
            socket.emit('download-progress', { progress, message: `下载中... ${progress}%` });
          }
        }
      });
      
      ytDlpProcess.stderr.on('data', (data) => {
        const output = data.toString();
        console.error('yt-dlp stderr:', output);
        
        // 智能网络错误分类和处理
        const errorTypes = {
          sslError: output.includes('handshake operation timed out') || output.includes('SSL'),
          connectionClosed: output.includes('远程主机强迫关闭了一个现有的连接') || output.includes('WinError 10054'),
          fragmentError: output.includes('fragment') && output.includes('not found'),
          timeoutError: output.includes('timeout') && !output.includes('handshake'),
          sabrError: output.includes('SABR streaming') || output.includes('Some web client https formats have been skipped'),
          poTokenError: output.includes('PO Token') || output.includes('po token') || output.includes('HTTP Error 403'),
          formatError: output.includes('No video formats found') || output.includes('Requested format is not available'),
          networkGeneral: output.includes('network') || output.includes('connection'),
          // 新增验证相关错误检测
          botVerification: output.includes('Sign in to confirm you\'re not a bot') || output.includes('bot verification') || output.includes('captcha'),
          loginRequired: output.includes('This video requires payment to watch') || output.includes('Sign in to confirm'),
          ageRestricted: output.includes('age-restricted') || output.includes('Sign in to confirm your age'),
          geoBlocked: output.includes('not available in your country') || output.includes('geo-blocked'),
          privateVideo: output.includes('Private video') || output.includes('This video is private')
        };
        
        const isNetworkError = Object.values(errorTypes).some(error => error);
        
        if (isNetworkError) {
          let errorMessage = '网络连接不稳定，正在重试...';
          
          if (errorTypes.botVerification) {
            errorMessage = '检测到机器人验证，正在使用超强绕过策略重试...';
            console.log('检测到机器人验证错误，已启用多客户端、cookies、地理绕过等超强策略...');
          } else if (errorTypes.loginRequired) {
            errorMessage = '视频需要登录访问，正在尝试多浏览器cookies验证...';
            console.log('检测到登录要求，正在使用多配置文件浏览器cookies进行验证...');
          } else if (errorTypes.ageRestricted) {
            errorMessage = '年龄限制视频，正在尝试超强绕过验证...';
            console.log('检测到年龄限制，正在使用成人模式+地理绕过+多客户端策略...');
          } else if (errorTypes.geoBlocked) {
            errorMessage = '地理位置限制，建议使用代理服务器...';
            console.log('检测到地理限制，可考虑配置代理绕过...');
          } else if (errorTypes.privateVideo) {
            errorMessage = '私有视频无法下载，请检查视频链接...';
            console.log('检测到私有视频，无法下载...');
          } else if (errorTypes.sslError) {
            errorMessage = 'SSL握手超时，正在重试...';
            console.log('检测到SSL握手错误，yt-dlp将自动重试...');
          } else if (errorTypes.connectionClosed) {
            errorMessage = '连接被远程主机关闭，正在重试...';
            console.log('检测到连接关闭错误，yt-dlp将自动重试...');
          } else if (errorTypes.fragmentError) {
            errorMessage = '视频片段下载失败，正在重试其他片段...';
            console.log('检测到片段下载错误，yt-dlp将继续尝试其他片段...');
          } else if (errorTypes.sabrError) {
            errorMessage = '检测到SABR流媒体格式问题，已使用web客户端配置重试...';
            console.log('检测到SABR格式问题，已配置web客户端和missing_pot参数避免此问题...');
          } else if (errorTypes.poTokenError) {
            errorMessage = '检测到PO Token验证问题，正在使用备用格式重试...';
            console.log('检测到PO Token错误，已配置missing_pot参数作为备选方案...');
          } else if (errorTypes.formatError) {
            errorMessage = '当前格式不可用，正在尝试其他格式...';
            console.log('检测到格式不可用错误，yt-dlp将尝试其他可用格式...');
          } else {
            console.log('检测到网络错误，yt-dlp将自动重试...');
          }
          
          if (batchId) {
            socket.emit('download-progress', { progress: 0, message: errorMessage, batchId });
          } else {
            socket.emit('download-progress', { progress: 0, message: errorMessage });
          }
        }
        
        // 解析进度（有时进度信息在 stderr 中）
        const progressMatch = output.match(/(\d+(?:\.\d+)?)%/);
        if (progressMatch) {
          const progress = parseFloat(progressMatch[1]);
          if (batchId) {
            socket.emit('download-progress', { progress, batchId });
          } else {
            socket.emit('download-progress', { progress, message: `下载中... ${progress}%` });
          }
        }
      });
      
      ytDlpProcess.on('close', async (code) => {
        if (code === 0) {
          // 下载完成，清除文件缓存
          downloader.clearCache();
          
          // 下载成功后，从保存的链接中删除对应的链接
          try {
            await removeCompletedLinkFromSaved(url);
          } catch (error) {
            console.error('删除已完成链接时出错:', error.message);
          }
          
          if (batchId) {
            socket.emit('download-complete', { 
              downloadPath, 
              title: videoInfo.title,
              batchId 
            });
          } else {
            socket.emit('download-complete', { 
              message: `下载完成！文件保存在: ${downloadPath}\\${videoInfo.title}`,
              downloadPath,
              title: videoInfo.title
            });
          }
        } else {
          const error = `下载失败，退出代码: ${code}`;
          if (batchId) {
            socket.emit('download-error', { error, batchId });
          } else {
            socket.emit('download-error', { error });
          }
          reject(new Error(error));
        }
      });
      
      ytDlpProcess.on('error', (err) => {
        console.error('yt-dlp进程错误:', err);
        reject(new Error(`yt-dlp进程错误: ${err.message}`));
      });
      
      } catch (error) {
        console.error('下载错误:', error);
        const errorMessage = error.message || '下载过程中发生错误';
        if (data.batchId) {
          socket.emit('download-error', { error: errorMessage, batchId: data.batchId });
        } else {
          socket.emit('download-error', { error: errorMessage });
        }
        reject(error);
      }
    });
  }

  // Socket事件监听器
  socket.on('download-video', async (data) => {
    try {
      await downloadWithRetry(data);
    } catch (error) {
      console.error('最终下载失败:', error.message);
      if (data.batchId) {
        socket.emit('download-error', { error: error.message, batchId: data.batchId });
      } else {
        socket.emit('download-error', { error: error.message });
      }
    }
  });

  socket.on('get-downloads', async () => {
    try {
      const files = await downloader.getDownloadedFiles();
      const filesByDate = await downloader.getDownloadedFilesByDate();
      socket.emit('downloads-list', { 
        files, 
        filesByDate,
        totalFiles: files.length 
      });
    } catch (error) {
      socket.emit('error', { message: error.message });
    }
  });

  // 重启服务器事件
  socket.on('restart-server', () => {
    console.log('收到重启服务器请求，来自:', socket.id);
    
    // 发送确认消息
    socket.emit('restart-acknowledged');
    
    // 延迟重启，给前端时间处理
    setTimeout(() => {
      console.log('正在重启服务器...');
      process.exit(0); // 退出进程，由进程管理器重启
    }, 1000);
  });

  socket.on('disconnect', () => {
    console.log('用户断开连接:', socket.id);
  });
});

// 启动服务器
server.listen(PORT, () => {
  console.log(`服务器运行在 http://localhost:${PORT}`);
});

module.exports = app;